#include "nnie_service.h"

#include <sys/uio.h>
#include <unistd.h>
#include <fcntl.h>
#include <math.h>
#include <iostream>
#include <fstream>

#include "hw_app_config.h"
#include "hw_app_log.h"
#include "opencv_api.h"

#include "hi_common.h"
#include "hi_debug.h"
#include "hi_dsp.h"

#include "sample_comm_svp.h"
#include "sample_comm_nnie.h"
#include "sample_comm_ive.h"

using namespace std;

// static std::mutex m_mutex;

static inline float sigmoid(float x)
{
    return static_cast<float>(1.f / (1.f + exp(-x)));
}

namespace HWApp {

NNIE::NNIE()
{
    m_yolo_version = GC_YOLO_VERSION::YOLO_UNKNOWN;

    LOG_INFO("NNIE constrctor");
}

NNIE::NNIE(GC_YOLO_VERSION yolo_version)
{
    m_yolo_version = yolo_version;

    LOG_INFO("NNIE constrctor, m_yolo_version=%d", m_yolo_version);
}

NNIE::~NNIE()
{
    close(m_fd_alg);
    m_fd_alg = -1;

    LOG_INFO("NNIE destory, m_yolo_version=%d", m_yolo_version);
}

int NNIE::GetFd() {
    std::lock_guard<std::mutex> lockFd(m_mutex); //该句柄fd非线程安全，每次使用时，需要做线程安全保护
    if (m_fd_alg <= 0) {
       m_fd_alg = ServiceRegister();
    }
    return m_fd_alg;
}

int NNIE::ServiceRegister() {
    int fd = open(ALG_SERVICE_NAME, O_RDWR); 
    if (fd <= 0) {
        LOG_ERROR("open %s failed, ret is: %i\n", ALG_SERVICE_NAME, fd);
        close(fd);
	    m_fd_alg = -1;
        return m_fd_alg;
    }
    m_fd_alg = fd;
    return m_fd_alg;
}

int NNIE::LoadModel(NnCreateParam* NnCreateParam)
{
    int ret = 0;
    sdc_extend_head_s* extend_head;
    char buf[1024] = {0};
    sdc_common_head_s *phead = (sdc_common_head_s *)buf;
    unsigned int uFileSize;
    sdc_mmz_alloc_s stMmzAddr;
    char * fileName = NnCreateParam->modelPath;
    if ((nullptr == NnCreateParam->modelPath)) {
        fprintf(stdout,"load model error, model path is null\n");
        return -1;
    }
    
    fprintf(stdout,"Load model, fileName:%s!\n", fileName);
    struct rsp_strcut 
    {
        sdc_common_head_s head;
        SVP_NNIE_MODEL_S model;
    }rsp_strcut_tmp;
    
    struct iovec iov[2] = 
    {
       {buf, sizeof(sdc_common_head_s) + sizeof(sdc_extend_head_s)},
       {NULL, MAX_MODULE_PATH}
    };
    //memset(&head, 0, sizeof(head));
    phead->version = SDC_VERSION;
    phead->url = SDC_URL_NNIE_MODEL;
    phead->method = SDC_METHOD_CREATE;
    phead->head_length = sizeof(sdc_common_head_s);
    phead->content_length = MAX_MODULE_PATH;
    /*模式 0，不带扩展头，默认内存方式加载*/
    if (NnCreateParam->loadModeModel == 0) {
        FILE *fp = fopen(fileName, "rb");
        if (fp == NULL) {
            fprintf(stdout,"modelfile fopen %s fail!\n", fileName);
            return -1;
        }
        ret = fseek(fp,0L,SEEK_END);
        if (ret != 0) {
            fprintf(stdout,"check nnie file SEEK_END, fseek fail.");
            fclose(fp);
            return -1;
        }
        
        uFileSize = ftell(fp);
        ret = fseek(fp,0L,SEEK_SET);
        if(0 != ret) {
            fprintf(stdout,"check nnie file SEEK_SET, fseek fail.");
            fclose(fp);
            return -1;
        }
        
        stMmzAddr.size = uFileSize;
        ret = m_utilsSrv->SDCMemAlloc(uFileSize, &stMmzAddr); // param 2: 0 no cache, 1 cache
        if (ret != stMmzAddr.size) {
            fprintf(stdout,"SDC_MmzAlloc ret %d, readsize %d", ret, stMmzAddr.size);
            return -1;
        }
        
        ret = fread((HI_VOID*)(uintptr_t)stMmzAddr.addr_virt, 1, stMmzAddr.size, fp);
        if (ret != stMmzAddr.size) {
            fprintf(stdout,"filesize %d, readsize %d", ret, stMmzAddr.size);
            return -1;
        }
        /*用户执行调用算法程序对传入文件进行解码*/
        if(SDC_ModelDecript(&stMmzAddr)) {
            fprintf(stdout,"SDC_ModelDecript Fail!");
            return -1; 
        }
        iov[1].iov_base = &stMmzAddr; 
        iov[0].iov_len = sizeof(sdc_common_head_s);
    } else if (NnCreateParam->loadModeModel == 1) {
        /*模式 1，带扩展头，扩展头参数指定为内存方式加载*/
        fstream fps(fileName, fstream::in | fstream::binary);
        if (!fps) {
            LOG_ERROR("open model file %s failed!", fileName);
            return -1;
        }
        // decrypt
        const char* temp_file = "/tmp/temp_wk";
        fstream fpt(temp_file, fstream::out | fstream::binary);
        if (!fpt) {
            LOG_ERROR("create temp file %s failed!", temp_file);
            return -1;
        }
        fps.seekg(0, ios::end);
        streamoff size = fps.tellg();
        fps.seekg(0, ios::beg);
        for (std::streamoff i = 0; i < size; i++)
        {
            fpt.put(fps.get() ^ 0x88); // TODO configable
        }
        fps.close();
        fpt.close();

        FILE *fp = fopen(temp_file, "rb");
        ret = fseek(fp, 0L, SEEK_END);
        if (ret != 0) {
            fprintf(stdout,"check nnie file SEEK_END, fseek fail.");
            fclose(fp);
            remove(temp_file);
            return -1;
        }
        
        uFileSize = ftell(fp);
        ret = fseek(fp, 0L, SEEK_SET);
        if(0 != ret) {
            fprintf(stdout,"check nnie file SEEK_SET, fseek fail.");
            fclose(fp);
            remove(temp_file);
            return -1;
        }

        stMmzAddr.size = uFileSize;
        ret = m_utilsSrv->SDCMemAlloc(uFileSize, &stMmzAddr); // param 2: 0 no cache, 1 cache
        if(ret != stMmzAddr.size) {
            fprintf(stdout,"SDC_MmzAlloc ret %d, readsize %d", ret, stMmzAddr.size);
            fclose(fp);
            remove(temp_file);
            return -1;
        }
        ret = fread((void*)(uintptr_t)stMmzAddr.addr_virt, 1, stMmzAddr.size, fp);
        fclose(fp);
        remove(temp_file);
        if(ret != stMmzAddr.size) {
            fprintf(stdout,"filesize %d, readsize %d", ret, stMmzAddr.size);
            return -1;
        }
        /*用户执行调用算法程序对传入文件进行解码*/
        if(SDC_ModelDecript(&stMmzAddr)) {
            fprintf(stdout,"SDC_ModelDecript Fail!");
            return -1;
        }
        extend_head = (sdc_extend_head_s *)&buf[phead->head_length];
        extend_head->type = 1;//NNIE_NNIE_MODEL_OP
        extend_head->length = sizeof(*extend_head);
        extend_head->reserve = 0;/*0 或者不带是内存方式，1 是文件名方式*/
        phead->head_length += sizeof(sdc_extend_head_s);
        iov[1].iov_base = &stMmzAddr; 
    } else {
        /*模式 2，带扩展头，扩展头参数指定为文件名方式加载*/
        extend_head = (sdc_extend_head_s *)&buf[phead->head_length];
        extend_head->type = 1;//NNIE_NNIE_MODEL_OP
        extend_head->length = sizeof(*extend_head);
        extend_head->reserve = 1;/*0 或者不带是内存方式，1 是文件名方式*/
        phead->head_length += sizeof(sdc_extend_head_s);
        iov[1].iov_base = fileName;//pcModelName; 
    }
    ret = writev(this->GetFd(), iov, 2);
    if (ret < 0) {
        fprintf(stdout,"creat nnie,write to algorithm.iaas.sdc fail: %m\n");
    }
    
    /*模型加载后立即释放*/
    //if (uiLoadMode < 2)mmz_free(fd_config, &stMmzAddr);
    
    ret = read(this->GetFd(), &rsp_strcut_tmp, sizeof(rsp_strcut_tmp));
    if(ret == -1) {
        fprintf(stdout,"get_channel_data fail: %m\n");
        return -1;
    }
    if(ret > sizeof(rsp_strcut_tmp)) {
        fprintf(stdout,"get_channel_data truncated, data len: %d > %zu\n", ret, sizeof(rsp_strcut_tmp));
        return -1;
    }
    if (ret < 0 || rsp_strcut_tmp.head.code != SDC_CODE_200 || rsp_strcut_tmp.head.content_length <= 0) {
        fprintf(stdout,"get nnie create response, read from algorithm.iaas.sdc fail,ret:%d, code=%d,length=%d\n", 
            ret, rsp_strcut_tmp.head.code, rsp_strcut_tmp.head.content_length);
    } else {
        // m_NnieModel.stModel = rsp_strcut_tmp.model;
        memcpy(&m_NnieModel.stModel, &rsp_strcut_tmp.model,sizeof(SVP_NNIE_MODEL_S));
        m_NnieParam.pstModel = &m_NnieModel.stModel;
    }
    return HW_OK;
}

int32_t NNIE::UnLoadModel()
{
    int nRet = -1;
    sdc_common_head_s head;
    struct iovec iov[2] = {
    [0] = {.iov_base = &head , .iov_len = sizeof(head)},
    [1] = {.iov_base = &m_NnieModel.stModel, .iov_len = sizeof(SVP_NNIE_MODEL_S)}};
    // fill head struct 
    memset(&head, 0, sizeof(head));
    head.version = SDC_VERSION;
    head.url = SDC_URL_NNIE_MODEL;
    head.method = SDC_METHOD_DELETE;
    head.head_length = sizeof(head);
    head.content_length = sizeof(SVP_NNIE_MODEL_S);
    nRet = writev(this->GetFd(), iov, sizeof(iov)/sizeof(iov[0]));
    if (nRet < 0)        {
        fprintf(stdout,"Errin SDC_UnLoadModel:failed to unload nnie module!\n");
        return -1;
    } 
}

int NNIE::ParamDeInit()
{
    sdc_mmz_alloc_s stMemParas;
    if (0 != m_NnieParam.stStepBuf.u64PhyAddr &&
        0 != m_NnieParam.stStepBuf.u64VirAddr) {
		stMemParas.addr_phy = m_NnieParam.stStepBuf.u64PhyAddr;
		stMemParas.addr_virt = m_NnieParam.stStepBuf.u64VirAddr;

        m_utilsSrv->SDCMemFree(&stMemParas);
		
		m_NnieParam.stStepBuf.u64PhyAddr = 0;
		m_NnieParam.stStepBuf.u64VirAddr = 0;
	}
	return HI_SUCCESS;
}

static HI_S32 NNIE_Yolov3_SoftwareDeinit(
    SAMPLE_SVP_NNIE_MODEL_PARAM_S* pstSoftWareParam,
    std::shared_ptr<UtilsService> utilsSrv)
{
    HI_S32 s32Ret = HI_SUCCESS;
	sdc_mmz_alloc_s stMemParas;
    SAMPLE_SVP_CHECK_EXPR_RET(NULL== pstSoftWareParam,HI_INVALID_VALUE,SAMPLE_SVP_ERR_LEVEL_ERROR,
        "Error, pstSoftWareParam can't be NULL!\n");
    if (0 != pstSoftWareParam->stGetResultTmpBuf.u64PhyAddr &&
        0 != pstSoftWareParam->stGetResultTmpBuf.u64VirAddr) {
		stMemParas.addr_phy = pstSoftWareParam->stGetResultTmpBuf.u64PhyAddr;
		stMemParas.addr_virt = pstSoftWareParam->stGetResultTmpBuf.u64VirAddr;

        utilsSrv->SDCMemFree(&stMemParas);
		
        pstSoftWareParam->stGetResultTmpBuf.u64PhyAddr = 0;
        pstSoftWareParam->stGetResultTmpBuf.u64VirAddr = 0;
        pstSoftWareParam->stDstRoi.u64PhyAddr = 0;
        pstSoftWareParam->stDstRoi.u64VirAddr = 0;
        pstSoftWareParam->stDstScore.u64PhyAddr = 0;
        pstSoftWareParam->stDstScore.u64VirAddr = 0;
        // pstSoftWareParam->stDstLandmark.u64PhyAddr = 0;
        // pstSoftWareParam->stDstLandmark.u64PhyAddr = 0;
        pstSoftWareParam->stClassRoiNum.u64PhyAddr = 0;
        pstSoftWareParam->stClassRoiNum.u64VirAddr = 0;
    }
    return s32Ret;
}

int32_t NNIE::NNIE_Yolov3_Deinit()
{
    HI_S32 s32Ret = HI_SUCCESS;
/*hardware deinit*/
    s32Ret = ParamDeInit();
    SAMPLE_SVP_CHECK_EXPR_TRACE(HI_SUCCESS != s32Ret,SAMPLE_SVP_ERR_LEVEL_ERROR,
        "Error,ParamDeInit failed!\n");
/*software deinit*/
    s32Ret = NNIE_Yolov3_SoftwareDeinit(&m_SoftwareParam, m_utilsSrv);
    SAMPLE_SVP_CHECK_EXPR_TRACE(HI_SUCCESS != s32Ret,SAMPLE_SVP_ERR_LEVEL_ERROR,
        "Error,NNIE_Yolov3_SoftwareDeinit failed!\n");
/*model deinit*/
    s32Ret = UnLoadModel();
    if (s32Ret != HW_OK)
    {
        fprintf(stdout,"Err in SDC_UnLoadModel\n");
    }
    return s32Ret;
}

// HI_U32 SAMPLE_SVP_NNIE_Yolov3_GetResultTmpBuf(SAMPLE_SVP_NNIE_PARAM_S*pstNnieParam,
//     SAMPLE_SVP_NNIE_MODEL_PARAM_S* pstSoftwareParam)
// {
//     HI_U32 u32TotalSize = 0;
//     HI_U32 u32AssistStackSize = 0;
//     HI_U32 u32TotalBboxNum = 0;
//     HI_U32 u32TotalBboxSize = 0;
//     HI_U32 u32DstBlobSize = 0;
//     HI_U32 u32MaxBlobSize = 0;
//     HI_U32 i = 0;

//     for (i = 0; i < pstNnieParam->pstModel->astSeg[0].u16DstNum; i++) {
//         u32DstBlobSize = pstNnieParam->pstModel->astSeg[0].astDstNode[i].unShape.stWhc.u32Width
//             *sizeof(HI_U32)*
//             pstNnieParam->pstModel->astSeg[0].astDstNode[i].unShape.stWhc.u32Height*
//             pstNnieParam->pstModel->astSeg[0].astDstNode[i].unShape.stWhc.u32Chn;
//         if (u32MaxBlobSize < u32DstBlobSize) {
//             u32MaxBlobSize = u32DstBlobSize;
//         }
//         u32TotalBboxNum += pstSoftwareParam->au32GridNumWidth[i] *
//             pstSoftwareParam->au32GridNumHeight[i] *
//             pstSoftwareParam->u32BboxNumEachGrid;
//     }
//     u32AssistStackSize = u32TotalBboxNum * sizeof(SAMPLE_SVP_NNIE_STACK_S);
//     u32TotalBboxSize = u32TotalBboxNum*sizeof(SAMPLE_SVP_NNIE_YOLOV3_BBOX_S);
//     u32TotalSize += (u32MaxBlobSize+u32AssistStackSize+u32TotalBboxSize);

//     return u32TotalSize;
// }

HI_S32 NNIE::Yolov3SoftwareInit()
{
    HI_S32 s32Ret = HI_SUCCESS;
    HI_U32 u32ClassNum = 0;
    HI_U32 u32TotalSize = 0;
    HI_U32 u32DstRoiSize = 0;
    HI_U32 u32DstScoreSize = 0;
    HI_U32 u32ClassRoiNumSize = 0;
    HI_U32 u32ClassLandmarksPointSize = 0;
    HI_U32 u32TmpBufTotalSize = 0;
    HI_U64 u64PhyAddr = 0;
    HI_U8* pu8VirAddr = NULL;
    sdc_mmz_alloc_s stMemParas;

    m_SoftwareParam.u32OriImHeight = m_NnieParam.astSegData[0].astSrc[0].unShape.stWhc.u32Height;
    m_SoftwareParam.u32OriImWidth = m_NnieParam.astSegData[0].astSrc[0].unShape.stWhc.u32Width;
    m_SoftwareParam.u32BboxNumEachGrid = BLOB_NUM; // 表示blob个数
    m_SoftwareParam.u32ClassNum = CLASS_NUM;

    m_SoftwareParam.u32NmsThresh  = (HI_U32)NMS_THRESH;
    m_SoftwareParam.u32ConfThresh = (HI_U32)gc_app_config.base_config.alg_config.yolo_conf_thresh;
    m_SoftwareParam.u32MaxRoiNum = 10;

    m_SoftwareParam.au32GridNumHeight[0] = 80;
    m_SoftwareParam.au32GridNumHeight[1] = 40;
    m_SoftwareParam.au32GridNumHeight[2] = 20;
    m_SoftwareParam.au32GridNumWidth[0] = 80;
    m_SoftwareParam.au32GridNumWidth[1] = 40;
    m_SoftwareParam.au32GridNumWidth[2] = 20;    

    switch (m_yolo_version) {
        case GC_YOLO_VERSION::YOLO_V5: 
        case GC_YOLO_VERSION::YOLO_V5_WITH_PLATE: {
            m_SoftwareParam.anchors[0][0] = {10, 13};
            m_SoftwareParam.anchors[0][1] = {16, 30};
            m_SoftwareParam.anchors[0][2] = {33, 23};

            m_SoftwareParam.anchors[1][0] = {30, 61};
            m_SoftwareParam.anchors[1][1] = {62, 45};
            m_SoftwareParam.anchors[1][2] = {59, 119};

            m_SoftwareParam.anchors[2][0] = {116, 90};
            m_SoftwareParam.anchors[2][1] = {156, 198};
            m_SoftwareParam.anchors[2][2] = {373, 326};
            break;
        }
        case GC_YOLO_VERSION::YOLO_V7: {
            m_SoftwareParam.anchors[0][0] = {12, 16};
            m_SoftwareParam.anchors[0][1] = {19, 36};
            m_SoftwareParam.anchors[0][2] = {40, 28};

            m_SoftwareParam.anchors[1][0] = {36, 75};
            m_SoftwareParam.anchors[1][1] = {76, 55};
            m_SoftwareParam.anchors[1][2] = {72, 146};

            m_SoftwareParam.anchors[2][0] = {142, 110};
            m_SoftwareParam.anchors[2][1] = {192, 243};
            m_SoftwareParam.anchors[2][2] = {459, 401};
            break;
        }
        case GC_YOLO_VERSION::YOLO_V5_ONLY_PLATE:
        case GC_YOLO_VERSION::YOLO_V5_ONLY_PLATE_CAR: {
            m_SoftwareParam.anchors[0][0] = {4, 5};
            m_SoftwareParam.anchors[0][1] = {8, 10};
            m_SoftwareParam.anchors[0][2] = {13, 16};

            m_SoftwareParam.anchors[1][0] = {23, 29};
            m_SoftwareParam.anchors[1][1] = {43, 55};
            m_SoftwareParam.anchors[1][2] = {73, 105};

            m_SoftwareParam.anchors[2][0] = {146, 217};
            m_SoftwareParam.anchors[2][1] = {231, 300};
            m_SoftwareParam.anchors[2][2] = {335, 433};
            break;
        }
        default:
            break;
    }

    /*Malloc assist buffer memory*/
    // u32ClassNum = m_SoftwareParam.u32ClassNum + 1;

    SAMPLE_SVP_CHECK_EXPR_RET(BLOB_NUM != m_NnieParam.pstModel->astSeg[0].u16DstNum,
        HI_FAILURE,SAMPLE_SVP_ERR_LEVEL_ERROR,"Error,m_NnieParam.pstModel->astSeg[0].u16DstNum(%d) should be %d!\n",
        m_NnieParam.pstModel->astSeg[0].u16DstNum, BLOB_NUM);
    // u32TmpBufTotalSize = SAMPLE_SVP_NNIE_Yolov3_GetResultTmpBuf(&m_NnieParam, &m_SoftwareParam);
    // u32DstRoiSize = SAMPLE_SVP_NNIE_ALIGN16(u32ClassNum*m_SoftwareParam.u32MaxRoiNum*sizeof(HI_U32)*SAMPLE_SVP_NNIE_COORDI_NUM);
    // u32DstScoreSize = SAMPLE_SVP_NNIE_ALIGN16(u32ClassNum*m_SoftwareParam.u32MaxRoiNum*sizeof(HI_U32)*GC_NNIE_OBJ_SCORE_NUM);
    // u32ClassRoiNumSize = SAMPLE_SVP_NNIE_ALIGN16(u32ClassNum*sizeof(HI_U32));
    // // u32TotalSize = u32TotalSize+u32DstRoiSize+u32DstScoreSize+u32ClassRoiNumSize+u32TmpBufTotalSize;
    // u32ClassLandmarksPointSize = SAMPLE_SVP_NNIE_ALIGN16(u32ClassNum*m_SoftwareParam.u32MaxRoiNum*sizeof(HI_U32)*LANDMARK_NUM);
    // u32TotalSize = u32TotalSize+u32DstRoiSize+u32DstScoreSize+u32ClassRoiNumSize+u32TmpBufTotalSize+u32ClassLandmarksPointSize;

    // LOG_DEBUG("m_SoftwareParam.u32MaxRoiNum=%d, u32ClassLandmarksPointSize=%d, u32TotalSize=%d", m_SoftwareParam.u32MaxRoiNum, u32ClassLandmarksPointSize, u32TotalSize);

    // s32Ret = m_utilsSrv->SDCMemAlloc(u32TotalSize, &stMemParas);
    // u64PhyAddr = stMemParas.addr_phy;
    // pu8VirAddr = (HI_U8 *)stMemParas.addr_virt;
    // u32TotalSize = stMemParas.size;

    // SAMPLE_SVP_CHECK_EXPR_RET(u32TotalSize != s32Ret,s32Ret,SAMPLE_SVP_ERR_LEVEL_ERROR,
    //     "Error,Malloc memory failed!\n");
    // memset(pu8VirAddr,0, u32TotalSize);
    // m_utilsSrv->SDCFlushCache(u64PhyAddr,(void*)pu8VirAddr,u32TotalSize);

   /*set each tmp buffer addr*/
    // m_SoftwareParam.stGetResultTmpBuf.u64PhyAddr = u64PhyAddr;
    // m_SoftwareParam.stGetResultTmpBuf.u64VirAddr = (HI_U64)(pu8VirAddr);

    /*set result blob*/
    // m_SoftwareParam.stDstRoi.enType = SVP_BLOB_TYPE_S32;
    // m_SoftwareParam.stDstRoi.u64PhyAddr = u64PhyAddr+u32TmpBufTotalSize;
    // m_SoftwareParam.stDstRoi.u64VirAddr = (HI_U64)(pu8VirAddr+u32TmpBufTotalSize);
    // m_SoftwareParam.stDstRoi.u32Stride = SAMPLE_SVP_NNIE_ALIGN16(u32ClassNum*
    //     m_SoftwareParam.u32MaxRoiNum*sizeof(HI_U32)*SAMPLE_SVP_NNIE_COORDI_NUM);
    // m_SoftwareParam.stDstRoi.u32Num = 1;
    // m_SoftwareParam.stDstRoi.unShape.stWhc.u32Chn = 1;
    // m_SoftwareParam.stDstRoi.unShape.stWhc.u32Height = 1;
    // m_SoftwareParam.stDstRoi.unShape.stWhc.u32Width = u32ClassNum*m_SoftwareParam.u32MaxRoiNum*SAMPLE_SVP_NNIE_COORDI_NUM;

    // m_SoftwareParam.stDstScore.enType = SVP_BLOB_TYPE_S32;
    // m_SoftwareParam.stDstScore.u64PhyAddr = u64PhyAddr+u32TmpBufTotalSize+u32DstRoiSize;
    // m_SoftwareParam.stDstScore.u64VirAddr = (HI_U64)(pu8VirAddr+u32TmpBufTotalSize+u32DstRoiSize);
    // m_SoftwareParam.stDstScore.u32Stride = SAMPLE_SVP_NNIE_ALIGN16(u32ClassNum*
    //     m_SoftwareParam.u32MaxRoiNum*sizeof(HI_U32));
    // m_SoftwareParam.stDstScore.u32Num = 1;
    // m_SoftwareParam.stDstScore.unShape.stWhc.u32Chn = 1;
    // m_SoftwareParam.stDstScore.unShape.stWhc.u32Height = 1;
    // m_SoftwareParam.stDstScore.unShape.stWhc.u32Width = u32ClassNum*m_SoftwareParam.u32MaxRoiNum;

    // m_SoftwareParam.stDstLandmark.enType = SVP_BLOB_TYPE_S32;
    // m_SoftwareParam.stDstLandmark.u64PhyAddr = u64PhyAddr+u32TmpBufTotalSize+u32DstRoiSize+u32DstScoreSize;
    // m_SoftwareParam.stDstLandmark.u64VirAddr = (HI_U64)(pu8VirAddr+u32TmpBufTotalSize+u32DstRoiSize+u32DstScoreSize);
    // m_SoftwareParam.stDstLandmark.u32Stride = SAMPLE_SVP_NNIE_ALIGN16(u32ClassNum*
    //     m_SoftwareParam.u32MaxRoiNum*sizeof(HI_U32)*LANDMARK_NUM);
    // m_SoftwareParam.stDstLandmark.u32Num = 1;
    // m_SoftwareParam.stDstLandmark.unShape.stWhc.u32Chn = 1;
    // m_SoftwareParam.stDstLandmark.unShape.stWhc.u32Height = 1;
    // m_SoftwareParam.stDstLandmark.unShape.stWhc.u32Width = u32ClassNum*m_SoftwareParam.u32MaxRoiNum*LANDMARK_NUM;

    // m_SoftwareParam.stClassRoiNum.enType = SVP_BLOB_TYPE_S32;
    // m_SoftwareParam.stClassRoiNum.u64PhyAddr = u64PhyAddr+u32TmpBufTotalSize+
    //     u32DstRoiSize+u32DstScoreSize+u32ClassLandmarksPointSize;
    // m_SoftwareParam.stClassRoiNum.u64VirAddr = (HI_U64)(pu8VirAddr+u32TmpBufTotalSize+
    //     u32DstRoiSize+u32DstScoreSize+u32ClassLandmarksPointSize);
    // // m_SoftwareParam.stClassRoiNum.u64PhyAddr = u64PhyAddr+u32TmpBufTotalSize+
    // //     u32DstRoiSize+u32DstScoreSize;
    // // m_SoftwareParam.stClassRoiNum.u64VirAddr = (HI_U64)(pu8VirAddr+u32TmpBufTotalSize+
    // //     u32DstRoiSize+u32DstScoreSize);
    // m_SoftwareParam.stClassRoiNum.u32Stride = SAMPLE_SVP_NNIE_ALIGN16(u32ClassNum*sizeof(HI_U32));
    // m_SoftwareParam.stClassRoiNum.u32Num = 1;
    // m_SoftwareParam.stClassRoiNum.unShape.stWhc.u32Chn = 1;
    // m_SoftwareParam.stClassRoiNum.unShape.stWhc.u32Height = 1;
    // m_SoftwareParam.stClassRoiNum.unShape.stWhc.u32Width = u32ClassNum;

    return HI_SUCCESS;
}

static HI_S32 SAMPLE_SVP_NNIE_FillForwardInfo(SAMPLE_SVP_NNIE_CFG_S *pstNnieCfg,
    SAMPLE_SVP_NNIE_PARAM_S *pstNnieParam)
{
	HI_U32 i = 0, j = 0;
	HI_U32 u32Offset = 0;
	HI_U32 u32Num = 0;

	for (i = 0; i < pstNnieParam->pstModel->u32NetSegNum; i++) {
		if(SVP_NNIE_NET_TYPE_ROI == pstNnieParam->pstModel->astSeg[i].enNetType) {
			pstNnieParam->astForwardWithBboxCtrl[i].enNnieId = pstNnieCfg->aenNnieCoreId[i];
			pstNnieParam->astForwardWithBboxCtrl[i].u32SrcNum = pstNnieParam->pstModel->astSeg[i].u16SrcNum;
			pstNnieParam->astForwardWithBboxCtrl[i].u32DstNum = pstNnieParam->pstModel->astSeg[i].u16DstNum;
			pstNnieParam->astForwardWithBboxCtrl[i].u32ProposalNum = 1;
			pstNnieParam->astForwardWithBboxCtrl[i].u32NetSegId = i;
			#if 0
                pstNnieParam->astForwardWithBboxCtrl[i].stTmpBuf = pstNnieParam->stTmpBuf;
                pstNnieParam->astForwardWithBboxCtrl[i].stTskBuf.u64PhyAddr= pstNnieParam->stTaskBuf.u64PhyAddr+u32Offset;
                pstNnieParam->astForwardWithBboxCtrl[i].stTskBuf.u64VirAddr= pstNnieParam->stTaskBuf.u64VirAddr+u32Offset;
                pstNnieParam->astForwardWithBboxCtrl[i].stTskBuf.u32Size= pstNnieParam->au32TaskBufSize[i];
			#endif
		} else if(SVP_NNIE_NET_TYPE_CNN == pstNnieParam->pstModel->astSeg[i].enNetType ||
            SVP_NNIE_NET_TYPE_RECURRENT== pstNnieParam->pstModel->astSeg[i].enNetType) {
			pstNnieParam->astForwardCtrl[i].enNnieId = pstNnieCfg->aenNnieCoreId[i];
			pstNnieParam->astForwardCtrl[i].u32SrcNum = pstNnieParam->pstModel->astSeg[i].u16SrcNum;
			pstNnieParam->astForwardCtrl[i].u32DstNum = pstNnieParam->pstModel->astSeg[i].u16DstNum;
			pstNnieParam->astForwardCtrl[i].u32NetSegId = i;
			#if 0
                pstNnieParam->astForwardCtrl[i].stTmpBuf = pstNnieParam->stTmpBuf;
                pstNnieParam->astForwardCtrl[i].stTskBuf.u64PhyAddr= pstNnieParam->stTaskBuf.u64PhyAddr+u32Offset;
                pstNnieParam->astForwardCtrl[i].stTskBuf.u64VirAddr= pstNnieParam->stTaskBuf.u64VirAddr+u32Offset;
                pstNnieParam->astForwardCtrl[i].stTskBuf.u32Size= pstNnieParam->au32TaskBufSize[i];
			#endif
		}
		u32Offset += pstNnieParam->au32TaskBufSize[i];/*这里赋值要审视下，好像参数没用*/

        /*fill src blob info*/
		for(j = 0; j < pstNnieParam->pstModel->astSeg[i].u16SrcNum; j++) {
            /*Recurrent blob*/
            if(SVP_BLOB_TYPE_SEQ_S32 == pstNnieParam->pstModel->astSeg[i].astSrcNode[j].enType) {
                pstNnieParam->astSegData[i].astSrc[j].enType = pstNnieParam->pstModel->astSeg[i].astSrcNode[j].enType;
                pstNnieParam->astSegData[i].astSrc[j].unShape.stSeq.u32Dim = pstNnieParam->pstModel->astSeg[i].astSrcNode[j].unShape.u32Dim;
                pstNnieParam->astSegData[i].astSrc[j].u32Num = pstNnieCfg->u32MaxInputNum;
                pstNnieParam->astSegData[i].astSrc[j].unShape.stSeq.u64VirAddrStep = pstNnieCfg->au64StepVirAddr[i*SAMPLE_SVP_NNIE_EACH_SEG_STEP_ADDR_NUM];
            } else{
    		    pstNnieParam->astSegData[i].astSrc[j].enType = pstNnieParam->pstModel->astSeg[i].astSrcNode[j].enType;
    	        pstNnieParam->astSegData[i].astSrc[j].unShape.stWhc.u32Chn = pstNnieParam->pstModel->astSeg[i].astSrcNode[j].unShape.stWhc.u32Chn;
    	        pstNnieParam->astSegData[i].astSrc[j].unShape.stWhc.u32Height = pstNnieParam->pstModel->astSeg[i].astSrcNode[j].unShape.stWhc.u32Height;
    	        pstNnieParam->astSegData[i].astSrc[j].unShape.stWhc.u32Width = pstNnieParam->pstModel->astSeg[i].astSrcNode[j].unShape.stWhc.u32Width;
    	        pstNnieParam->astSegData[i].astSrc[j].u32Num = pstNnieCfg->u32MaxInputNum;
            }
	    }

        /*fill dst blob info*/
		if (SVP_NNIE_NET_TYPE_ROI == pstNnieParam->pstModel->astSeg[i].enNetType) {
			u32Num = pstNnieCfg->u32MaxRoiNum*pstNnieCfg->u32MaxInputNum;
		} else {
			u32Num = pstNnieCfg->u32MaxInputNum;
		}

		for (j = 0; j < pstNnieParam->pstModel->astSeg[i].u16DstNum; j++) {
            if(SVP_BLOB_TYPE_SEQ_S32 == pstNnieParam->pstModel->astSeg[i].astDstNode[j].enType) {
    			pstNnieParam->astSegData[i].astDst[j].enType = pstNnieParam->pstModel->astSeg[i].astDstNode[j].enType;
    			pstNnieParam->astSegData[i].astDst[j].unShape.stSeq.u32Dim =
                    pstNnieParam->pstModel->astSeg[i].astDstNode[j].unShape.u32Dim;
                pstNnieParam->astSegData[i].astDst[j].u32Num = u32Num;
                pstNnieParam->astSegData[i].astDst[j].unShape.stSeq.u64VirAddrStep =
                    pstNnieCfg->au64StepVirAddr[i*SAMPLE_SVP_NNIE_EACH_SEG_STEP_ADDR_NUM+1];
            } else {
    		    pstNnieParam->astSegData[i].astDst[j].enType = pstNnieParam->pstModel->astSeg[i].astDstNode[j].enType;
    		    pstNnieParam->astSegData[i].astDst[j].unShape.stWhc.u32Chn = pstNnieParam->pstModel->astSeg[i].astDstNode[j].unShape.stWhc.u32Chn;
    		    pstNnieParam->astSegData[i].astDst[j].unShape.stWhc.u32Height = pstNnieParam->pstModel->astSeg[i].astDstNode[j].unShape.stWhc.u32Height;
    		    pstNnieParam->astSegData[i].astDst[j].unShape.stWhc.u32Width = pstNnieParam->pstModel->astSeg[i].astDstNode[j].unShape.stWhc.u32Width;
    		    pstNnieParam->astSegData[i].astDst[j].u32Num = u32Num;
            }
		}
	}
	return HI_SUCCESS;
}

static void SAMPLE_SVP_NNIE_GetBlobMemSize(SVP_NNIE_NODE_S astNnieNode[], HI_U32 u32NodeNum,
	HI_U32 u32TotalStep,SVP_BLOB_S astBlob[], HI_U32 u32Align, HI_U32* pu32TotalSize,HI_U32 au32BlobSize[])
{
	HI_U32 i = 0;
	HI_U32 u32Size = 0;
	HI_U32 u32Stride = 0;

	for(i = 0; i < u32NodeNum; i++) {
		if(SVP_BLOB_TYPE_S32== astNnieNode[i].enType||SVP_BLOB_TYPE_VEC_S32== astNnieNode[i].enType||
            SVP_BLOB_TYPE_SEQ_S32== astNnieNode[i].enType) {
			u32Size = sizeof(HI_U32);
		} else {
			u32Size = sizeof(HI_U8);
		}
        if(SVP_BLOB_TYPE_SEQ_S32 == astNnieNode[i].enType) {
            if(SAMPLE_SVP_NNIE_ALIGN_16 == u32Align) {
    			u32Stride = SAMPLE_SVP_NNIE_ALIGN16(astNnieNode[i].unShape.u32Dim*u32Size);
    		} else {
    			u32Stride = SAMPLE_SVP_NNIE_ALIGN32(astNnieNode[i].unShape.u32Dim*u32Size);
    		}
            au32BlobSize[i] = u32TotalStep*u32Stride;
        } else {
            if(SAMPLE_SVP_NNIE_ALIGN_16 == u32Align) {
    			u32Stride = SAMPLE_SVP_NNIE_ALIGN16(astNnieNode[i].unShape.stWhc.u32Width*u32Size);
    		} else {
    			u32Stride = SAMPLE_SVP_NNIE_ALIGN32(astNnieNode[i].unShape.stWhc.u32Width*u32Size);
    		}
    		au32BlobSize[i] = astBlob[i].u32Num*u32Stride*astNnieNode[i].unShape.stWhc.u32Height*
    			astNnieNode[i].unShape.stWhc.u32Chn;
        }
		*pu32TotalSize += au32BlobSize[i];
	    astBlob[i].u32Stride = u32Stride;
	}
}

static HI_S32 SAMPLE_SVP_NNIE_GetTaskAndBlobBufSize(SAMPLE_SVP_NNIE_CFG_S *pstNnieCfg,
    SAMPLE_SVP_NNIE_PARAM_S *pstNnieParam,HI_U32*pu32TotalTaskBufSize, HI_U32*pu32TmpBufSize,
    SAMPLE_SVP_NNIE_BLOB_SIZE_S astBlobSize[],HI_U32*pu32TotalSize)
{
	HI_S32 s32Ret = HI_SUCCESS;
	HI_U32 i = 0, j = 0;
    HI_U32 u32TotalStep = 0;

	/*calculate Blob mem size*/
	for(i = 0; i < pstNnieParam->pstModel->u32NetSegNum; i++) {
        if(SVP_NNIE_NET_TYPE_RECURRENT == pstNnieParam->pstModel->astSeg[i].enNetType) {
            for(j = 0; j < pstNnieParam->astSegData[i].astSrc[0].u32Num; j++) {
                u32TotalStep += *((HI_S32*)pstNnieParam->astSegData[i].astSrc[0].unShape.stSeq.u64VirAddrStep+j);
            }
        }
		/*the first seg's Src Blob mem size, other seg's src blobs from the output blobs of
		those segs before it or from software output results*/
		if(i == 0) {
			SAMPLE_SVP_NNIE_GetBlobMemSize(&(pstNnieParam->pstModel->astSeg[i].astSrcNode[0]),
				pstNnieParam->pstModel->astSeg[i].u16SrcNum,u32TotalStep,&(pstNnieParam->astSegData[i].astSrc[0]),
				SAMPLE_SVP_NNIE_ALIGN_16, pu32TotalSize, &(astBlobSize[i].au32SrcSize[0]));
		}

		/*Get each seg's Dst Blob mem size*/
		SAMPLE_SVP_NNIE_GetBlobMemSize(&(pstNnieParam->pstModel->astSeg[i].astDstNode[0]),
			pstNnieParam->pstModel->astSeg[i].u16DstNum,u32TotalStep,&(pstNnieParam->astSegData[i].astDst[0]),
			SAMPLE_SVP_NNIE_ALIGN_16, pu32TotalSize, &(astBlobSize[i].au32DstSize[0]));
	}
	return s32Ret;
}

HI_S32 SAMPLE_SVP_NNIE_ParamInit(SAMPLE_SVP_NNIE_CFG_S *pstNnieCfg, SAMPLE_SVP_NNIE_PARAM_S *pstNnieParam, std::shared_ptr<UtilsService> uServ)
{
    HI_U32 i = 0, j = 0;
    HI_U32 u32TotalSize = 0;
    HI_U32 u32TotalTaskBufSize = 0;
    HI_U32 u32TmpBufSize = 0;
    HI_S32 s32Ret = HI_SUCCESS;
    HI_U64 u64PhyAddr = 0;
    HI_U8 *pu8VirAddr = NULL;
    SAMPLE_SVP_NNIE_BLOB_SIZE_S astBlobSize[SVP_NNIE_MAX_NET_SEG_NUM] = {0};
    sdc_mmz_alloc_s stMemParas;

    /*fill forward info*/
    s32Ret = SAMPLE_SVP_NNIE_FillForwardInfo(pstNnieCfg, pstNnieParam);
    SAMPLE_SVP_CHECK_EXPR_RET(HI_SUCCESS != s32Ret,s32Ret,SAMPLE_SVP_ERR_LEVEL_ERROR,
        "Error,SAMPLE_SVP_NNIE_FillForwardCtrl failed!\n");

    /*Get taskInfo and Blob mem size*/
    s32Ret = SAMPLE_SVP_NNIE_GetTaskAndBlobBufSize(pstNnieCfg, pstNnieParam, &u32TotalTaskBufSize,
        &u32TmpBufSize,astBlobSize,&u32TotalSize);
    SAMPLE_SVP_CHECK_EXPR_RET(HI_SUCCESS != s32Ret,s32Ret,SAMPLE_SVP_ERR_LEVEL_ERROR,
        "Error,SAMPLE_SVP_NNIE_GetTaskAndBlobBufSize failed!\n");

    /*Malloc mem*/
    s32Ret = uServ->SDCMemAlloc(u32TotalSize, &stMemParas);
    u64PhyAddr = stMemParas.addr_phy;
    pu8VirAddr = (HI_U8 *)stMemParas.addr_virt; //  

    fprintf(stdout,"SDC_MemAlloc u32TotalSize %d, size %d", u32TotalSize, stMemParas.size);

    u32TotalSize = stMemParas.size;

    SAMPLE_SVP_CHECK_EXPR_RET(u32TotalSize != s32Ret,s32Ret,SAMPLE_SVP_ERR_LEVEL_ERROR,
        "Error,Malloc memory failed,u32TotalSize:%d,s32Ret:%d!\n", u32TotalSize, s32Ret);

    memset(pu8VirAddr, 0, u32TotalSize);
    s32Ret = uServ->SDCFlushCache(u64PhyAddr, (void*)pu8VirAddr,u32TotalSize);
    LOG_IF_FAIL(s32Ret == HI_SUCCESS, "SDCFlushCache error");

    /*fill each blob's mem addr*/
    u64PhyAddr =  u64PhyAddr;//+u32TotalTaskBufSize+u32TmpBufSize;
    pu8VirAddr = pu8VirAddr;//+u32TotalTaskBufSize+u32TmpBufSize;
    for (i = 0; i < pstNnieParam->pstModel->u32NetSegNum; i++) {
        /*first seg has src blobs, other seg's src blobs from the output blobs of
        those segs before it or from software output results*/
        if(0 == i) {
            for(j = 0; j < pstNnieParam->pstModel->astSeg[i].u16SrcNum; j++) {
                if (j != 0) {
                    u64PhyAddr += astBlobSize[i].au32SrcSize[j-1];
                    pu8VirAddr += astBlobSize[i].au32SrcSize[j-1];
                }
                pstNnieParam->astSegData[i].astSrc[j].u64PhyAddr = u64PhyAddr;
                pstNnieParam->astSegData[i].astSrc[j].u64VirAddr = (HI_U64)pu8VirAddr;
            }
            u64PhyAddr += astBlobSize[i].au32SrcSize[j-1];
            pu8VirAddr += astBlobSize[i].au32SrcSize[j-1];
        }

        /*fill the mem addrs of each seg's output blobs*/
        for (j = 0; j < pstNnieParam->pstModel->astSeg[i].u16DstNum; j++) {
            if (j != 0) {
                u64PhyAddr += astBlobSize[i].au32DstSize[j-1];
                pu8VirAddr += astBlobSize[i].au32DstSize[j-1];
            }
            pstNnieParam->astSegData[i].astDst[j].u64PhyAddr = u64PhyAddr;
            pstNnieParam->astSegData[i].astDst[j].u64VirAddr = (HI_U64)pu8VirAddr;
        }
        u64PhyAddr += astBlobSize[i].au32DstSize[j-1];
        pu8VirAddr += astBlobSize[i].au32DstSize[j-1];
    }
    return HI_SUCCESS;
}

int NNIE::NnieParamInit()
{
	HI_S32 s32Ret = HI_SUCCESS;

	s32Ret = SAMPLE_SVP_NNIE_ParamInit(&m_NnieCfg, &m_NnieParam, m_utilsSrv);
	SAMPLE_SVP_CHECK_EXPR_GOTO(HI_SUCCESS != s32Ret,FAIL,SAMPLE_SVP_ERR_LEVEL_ERROR,
		"Error, SAMPLE_SVP_NNIE_ParamInit failed!\n");
	return s32Ret;
FAIL:
	s32Ret = ParamDeInit();
	SAMPLE_SVP_CHECK_EXPR_RET(HI_SUCCESS != s32Ret,s32Ret,SAMPLE_SVP_ERR_LEVEL_ERROR,
		"Error, SAMPLE_COMM_SVP_NNIE_ParamDeinit failed!\n");
	return HI_FAILURE;
}

int32_t NNIE::SAMPLE_SVP_NNIE_Yolov3_ParamInit()
{
    HI_S32 s32Ret = HI_SUCCESS;
    /*init hardware para*/
    s32Ret = NnieParamInit();
    SAMPLE_SVP_CHECK_EXPR_GOTO(HI_SUCCESS != s32Ret,INIT_FAIL_0,SAMPLE_SVP_ERR_LEVEL_ERROR,
        "Error(%#x),NnieParamInit failed!\n",s32Ret);

    if (m_yolo_version != GC_YOLO_VERSION::YOLO_UNKNOWN) {
        /*init software para*/
        s32Ret = Yolov3SoftwareInit();
        SAMPLE_SVP_CHECK_EXPR_GOTO(HI_SUCCESS != s32Ret,INIT_FAIL_0,SAMPLE_SVP_ERR_LEVEL_ERROR,
            "Error(%#x),Yolov3SoftwareInit failed!\n",s32Ret);
    }

    return s32Ret;
INIT_FAIL_0:
    s32Ret = NNIE_Yolov3_Deinit();
    SAMPLE_SVP_CHECK_EXPR_RET(HI_SUCCESS != s32Ret,s32Ret,SAMPLE_SVP_ERR_LEVEL_ERROR,
            "Error(%#x),NNIE_Yolov3_Deinit failed!\n",s32Ret);
    return HI_FAILURE;
}

int32_t SaveYuv(HI_U8 *data)
{
    int ret;
    unsigned char yuvName[DEMO_FILE_NAME_LEN] = {0};

    if (data) {
        FILE *file1 = NULL;
        sprintf_s((char *)yuvName, DEMO_FILE_NAME_LEN, "./src4forward.yuv");
        file1 = fopen((const char *)yuvName, "w");
        if (file1) {
            fwrite(data, sizeof(unsigned char),
                MODEL_INPUT_SIZE_HEIGHT * MODEL_INPUT_SIZE_WIDTH * DL_IMAGE_YUV_CHANNEL / DL_IMAGE_UV_HALF, file1);
            fclose(file1);
            LOG_DEBUG("[%s][%d]. yuvName: %s size %dx%d\n",
                __func__, __LINE__, yuvName, MODEL_INPUT_SIZE_WIDTH,
                MODEL_INPUT_SIZE_HEIGHT);
        }
    }
}

HI_S32 NNIE::FillSrcData(const ImageInfo& img)
{
    return FillSrcData((char*) img.data);
}

HI_S32 NNIE::FillSrcData(HI_CHAR *pcSrcYUV)
{
    FILE*  fp = NULL;
    HI_U32 i =0, j = 0, n = 0;
    HI_U32 u32Height = 0, u32Width = 0, u32Chn = 0, u32Stride = 0, u32Dim = 0;
    HI_U32 u32VarSize = 0;
    HI_S32 s32Ret = HI_SUCCESS;
    HI_U8* pu8PicAddr = NULL;
    HI_U32* pu32StepAddr = NULL;
    HI_U32 u32TotalStepNum = 0;
	HI_U8* pData = (HI_U8*)pcSrcYUV;

	HI_BOOL bRBG2BGR = HI_TRUE; // 送入模型的通道顺序是否调整
    HI_U32 u32SegIdx = 0;
    HI_U32 u32NodeIdx = 0;
	// RBG => BGR
	#define B_BASE_OFFSET (1*u32Stride*u32Height)
	#define G_BASE_OFFSET (2*u32Stride*u32Height)
	#define R_BASE_OFFSET (0*u32Stride*u32Height)
	HI_U8 *p_B_data = HI_NULL; 
	HI_U8 *p_G_data = HI_NULL;
	HI_U8 *p_R_data = HI_NULL;

    /*get data size*/
    if (SVP_BLOB_TYPE_U8 <= m_NnieParam.astSegData[u32SegIdx].astSrc[u32NodeIdx].enType &&
        SVP_BLOB_TYPE_YVU422SP >= m_NnieParam.astSegData[u32SegIdx].astSrc[u32NodeIdx].enType) {
        u32VarSize = sizeof(HI_U8);
    } else {
        u32VarSize = sizeof(HI_U32);
    }

    /*fill src data*/
    if(SVP_BLOB_TYPE_SEQ_S32 == m_NnieParam.astSegData[u32SegIdx].astSrc[u32NodeIdx].enType) {
        u32Dim = m_NnieParam.astSegData[u32SegIdx].astSrc[u32NodeIdx].unShape.stSeq.u32Dim;
        u32Stride = m_NnieParam.astSegData[u32SegIdx].astSrc[u32NodeIdx].u32Stride;
        pu32StepAddr = (HI_U32*)(m_NnieParam.astSegData[u32SegIdx].astSrc[u32NodeIdx].unShape.stSeq.u64VirAddrStep);
        pu8PicAddr = (HI_U8*)(m_NnieParam.astSegData[u32SegIdx].astSrc[u32NodeIdx].u64VirAddr);
        for(n = 0; n < m_NnieParam.astSegData[u32SegIdx].astSrc[u32NodeIdx].u32Num; n++) {
            for(i = 0;i < *(pu32StepAddr+n); i++) {
                s32Ret = fread(pu8PicAddr,u32Dim*u32VarSize,1,fp);
                SAMPLE_SVP_CHECK_EXPR_GOTO(1 != s32Ret,FAIL,SAMPLE_SVP_ERR_LEVEL_ERROR,"Error,Read image file failed!\n");
                pu8PicAddr += u32Stride;
            }
            u32TotalStepNum += *(pu32StepAddr+n);
        }
        m_utilsSrv->SDCFlushCache(m_NnieParam.astSegData[u32SegIdx].astSrc[u32NodeIdx].u64PhyAddr,
            (HI_VOID *) m_NnieParam.astSegData[u32SegIdx].astSrc[u32NodeIdx].u64VirAddr,
            u32TotalStepNum*u32Stride);
    } else {
        u32Height = m_NnieParam.astSegData[u32SegIdx].astSrc[u32NodeIdx].unShape.stWhc.u32Height;
        u32Width = m_NnieParam.astSegData[u32SegIdx].astSrc[u32NodeIdx].unShape.stWhc.u32Width;
        u32Chn = m_NnieParam.astSegData[u32SegIdx].astSrc[u32NodeIdx].unShape.stWhc.u32Chn;
        u32Stride = m_NnieParam.astSegData[u32SegIdx].astSrc[u32NodeIdx].u32Stride;
        pu8PicAddr = (HI_U8*)(m_NnieParam.astSegData[u32SegIdx].astSrc[u32NodeIdx].u64VirAddr);
        if(SVP_BLOB_TYPE_YVU420SP== m_NnieParam.astSegData[u32SegIdx].astSrc[u32NodeIdx].enType) {
            for(n = 0; n < m_NnieParam.astSegData[u32SegIdx].astSrc[u32NodeIdx].u32Num; n++) {
                UINT32 uiDataSize = u32Width * u32Height * 3 / 2;
                memset_s(pu8PicAddr, uiDataSize, 0, uiDataSize);
                memcpy_s(pu8PicAddr, uiDataSize, pData, uiDataSize);
                // SaveYuv(pData);
            }
        } else if(SVP_BLOB_TYPE_YVU422SP== m_NnieParam.astSegData[u32SegIdx].astSrc[u32NodeIdx].enType) {
            for(n = 0; n < m_NnieParam.astSegData[u32SegIdx].astSrc[u32NodeIdx].u32Num; n++) {
                for(i = 0; i < u32Height*2; i++) {
                    s32Ret = fread(pu8PicAddr,u32Width*u32VarSize,1,fp);
                    SAMPLE_SVP_CHECK_EXPR_GOTO(1 != s32Ret,FAIL,SAMPLE_SVP_ERR_LEVEL_ERROR,"Error,Read image file failed!\n");
                    pu8PicAddr += u32Stride;
                }
            }
        } else {
			if(bRBG2BGR) {
                // RBG => BGR
				p_B_data = pData + B_BASE_OFFSET;
				p_G_data = pData + G_BASE_OFFSET;
				p_R_data = pData + R_BASE_OFFSET;
			}
            for(n = 0; n < m_NnieParam.astSegData[u32SegIdx].astSrc[u32NodeIdx].u32Num; n++) {
                for(i = 0;i < u32Chn; i++) {
                    for(j = 0; j < u32Height; j++) {
						if(HI_NULL != fp) {  
							s32Ret = fread(pu8PicAddr,u32Width*u32VarSize,1,fp);
							SAMPLE_SVP_CHECK_EXPR_GOTO(1 != s32Ret,FAIL,SAMPLE_SVP_ERR_LEVEL_ERROR,"Error,Read image file failed!\n");
						} else if(HI_NULL != m_NnieCfg.pszBGR) {
							//printf("u32Width*u32VarSize = %d\n", u32Width*u32VarSize);
							if(bRBG2BGR) {
                                 // RBG => BGR
							    if(u32Chn == 0) {
                                    //copy B
									memcpy_s(pu8PicAddr, u32Width*u32VarSize, p_B_data, u32Width*u32VarSize);  
									p_B_data += u32Stride;
								} else if(u32Chn == 1) {
                                    //copy G
									memcpy_s(pu8PicAddr, u32Width*u32VarSize, p_G_data, u32Width*u32VarSize);  
									p_G_data += u32Stride;
								} else {
                                    // copy R
									memcpy_s(pu8PicAddr, u32Width*u32VarSize, p_R_data, u32Width*u32VarSize);  
									p_R_data += u32Stride;
								}
							} else {
								memcpy_s(pu8PicAddr, u32Width*u32VarSize, pData, u32Width*u32VarSize);  
								pData += u32Stride;
							}
						}
						pu8PicAddr += u32Stride;
                    }
                }
            }
        }
        m_utilsSrv->SDCFlushCache(m_NnieParam.astSegData[u32SegIdx].astSrc[u32NodeIdx].u64PhyAddr,
            (HI_VOID *) m_NnieParam.astSegData[u32SegIdx].astSrc[u32NodeIdx].u64VirAddr,
            m_NnieParam.astSegData[u32SegIdx].astSrc[u32NodeIdx].u32Num*u32Chn*u32Height*u32Stride);
    }
    if(fp != HI_NULL)
        fclose(fp);
    return HI_SUCCESS;

FAIL:
    if(fp != HI_NULL)
        fclose(fp);
    fclose(fp);
    return HI_FAILURE;
}

int NNIE::SDCNnieForward(sdc_nnie_forward_s *p_sdc_nnie_forward)
{
    int nRet;
    int fd_algorithm = GetFd();;
    sdc_common_head_s rsp_head;
    sdc_common_head_s head;
    struct iovec iov[2] = 
    {
        [0] = {.iov_base = &head, .iov_len = sizeof(head)},
        [1] = {.iov_base = p_sdc_nnie_forward, .iov_len = sizeof(*p_sdc_nnie_forward)}
    };
    // fill head struct 
    memset(&head, 0, sizeof(head));
    head.version = SDC_VERSION;
    head.url = SDC_URL_NNIE_FORWARD;
    head.method = SDC_METHOD_GET;
    head.head_length = sizeof(head);
    head.content_length = sizeof(*p_sdc_nnie_forward);

    // write request
    nRet = writev(fd_algorithm, iov, sizeof(iov)/sizeof(iov[0]));
    if (nRet < 0)
    {
        LOG_ERROR("Error:failed to write info to NNIE Forward,nRet:%d!\n",nRet);
        return ERR;
    }
    // read response
    iov[0].iov_base = &rsp_head;
    iov[0].iov_len = sizeof(rsp_head);
    nRet = readv(fd_algorithm, iov, 1);
    if (rsp_head.code != SDC_CODE_200 || nRet < 0)
    {
        LOG_ERROR("Error:failed to read info from NNIE Forward,nRet:%d,rsp_head.code:%d!\n",
            nRet, rsp_head.code);
        return ERR;
    } 
    return HW_OK;
}

/******************************************************************************
* function : NNIE Forward
******************************************************************************/
HI_S32 NNIE::Forward(NNIE_DATA_INDEX_S* pstInputDataIdx, NNIE_DATA_INDEX_S* pstProcSegIdx)
{
    HI_S32 s32Ret = HI_SUCCESS;
    HI_U32 i = 0, j = 0;
    sdc_nnie_forward_s sdc_nnie_forward;

    /*set input blob according to node name*/
    if(pstInputDataIdx->u32SegIdx != pstProcSegIdx->u32SegIdx) {
        for(i = 0; i < m_NnieParam.pstModel->astSeg[pstProcSegIdx->u32SegIdx].u16SrcNum; i++) {
            for(j = 0; j < m_NnieParam.pstModel->astSeg[pstInputDataIdx->u32SegIdx].u16DstNum; j++) {
                if(0 == strncmp(m_NnieParam.pstModel->astSeg[pstInputDataIdx->u32SegIdx].astDstNode[j].szName,
                    m_NnieParam.pstModel->astSeg[pstProcSegIdx->u32SegIdx].astSrcNode[i].szName,
                    SVP_NNIE_NODE_NAME_LEN)) {
                    m_NnieParam.astSegData[pstProcSegIdx->u32SegIdx].astSrc[i] =
                        m_NnieParam.astSegData[pstInputDataIdx->u32SegIdx].astDst[j];
                    break;
                }
            }
            SAMPLE_SVP_CHECK_EXPR_RET((j == m_NnieParam.pstModel->astSeg[pstInputDataIdx->u32SegIdx].u16DstNum),
                HI_FAILURE,SAMPLE_SVP_ERR_LEVEL_ERROR,"Error,can't find %d-th seg's %d-th src blob!\n",
                pstProcSegIdx->u32SegIdx,i);
        }
    }

    /*NNIE_Forward*/
    memcpy(&sdc_nnie_forward.model, m_NnieParam.pstModel,  sizeof(SVP_NNIE_MODEL_S));
    sdc_nnie_forward.forward_ctrl.max_batch_num = 1;
	sdc_nnie_forward.forward_ctrl.max_bbox_num = 0;/*此处需要根据算法模型的ROI个数决定，max_bbox_num = max_roi_num(ROI个数)*/
    sdc_nnie_forward.forward_ctrl.netseg_id = m_NnieParam.astForwardCtrl[pstProcSegIdx->u32SegIdx].u32NetSegId;
    
    memcpy(sdc_nnie_forward.astSrc, m_NnieParam.astSegData[pstProcSegIdx->u32SegIdx].astSrc,  16*sizeof(SVP_DST_BLOB_S));
    memcpy(sdc_nnie_forward.astDst, m_NnieParam.astSegData[pstProcSegIdx->u32SegIdx].astDst,  16*sizeof(SVP_DST_BLOB_S));

    s32Ret = SDCNnieForward(&sdc_nnie_forward);
    if (s32Ret != HW_OK) {
		fprintf(stderr, "Err in SDC_Nnie_Forward, s32Ret: %d\n", s32Ret);
		return ERR;
	}
    return s32Ret;
}

static HI_FLOAT QuickExp(HI_S32 s32Value)
{
    if( s32Value & 0x80000000) {
        s32Value = ~s32Value + 0x00000001;
        return s_af32ExpCoef[5][s32Value & 0x0000000F] * s_af32ExpCoef[6][(s32Value>>4) & 0x0000000F] * s_af32ExpCoef[7][(s32Value>>8) & 0x0000000F] * s_af32ExpCoef[8][(s32Value>>12) & 0x0000000F] * s_af32ExpCoef[9][(s32Value>>16) & 0x0000000F ];
    } else {
        return s_af32ExpCoef[0][s32Value & 0x0000000F] * s_af32ExpCoef[1][(s32Value>>4) & 0x0000000F] * s_af32ExpCoef[2][(s32Value>>8) & 0x0000000F] * s_af32ExpCoef[3][(s32Value>>12) & 0x0000000F] * s_af32ExpCoef[4][(s32Value>>16) & 0x0000000F ];
    }
}

static HI_S32 SoftMax(HI_FLOAT* pf32Src, HI_U32 u32Num)
{
    HI_FLOAT f32Max = 0;
    HI_FLOAT f32Sum = PROTECT_VAL;
    HI_U32 i = 0;

    for (i = 0; i < u32Num; ++i) {
        if(f32Max < pf32Src[i]) {
            f32Max = pf32Src[i];
        }
    }

    for (i = 0; i < u32Num; ++i) {
        pf32Src[i] = (HI_FLOAT)QuickExp((HI_S32)((pf32Src[i] - f32Max)*SAMPLE_SVP_NNIE_QUANT_BASE));
        f32Sum += pf32Src[i];
    }

    for (i = 0; i < u32Num; ++i) {
        pf32Src[i] /= f32Sum;
    }
    return HI_SUCCESS;
}

static HI_FLOAT GetMaxScoreVal(HI_FLOAT *pf32Val,HI_U32 u32Num, HI_U32 * pu32MaxValueIndex)
{
    HI_U32 i = 0;
    HI_FLOAT f32MaxTmp = 0;

    f32MaxTmp = pf32Val[0];
    *pu32MaxValueIndex = 0;
    for (i = 1; i < u32Num; i++)
    {
        if(pf32Val[i] > f32MaxTmp)
        {
            f32MaxTmp = pf32Val[i];
            *pu32MaxValueIndex = i;
        }
    }

    return f32MaxTmp;
}

static void QsortDescentInplace(std::vector<ObjBox>& faceobjects, int left, int right)
{
    int i = left;
    int j = right;
    float p = faceobjects[(left + right) / 2].fScore;

    while (i <= j) {
        while (faceobjects[i].fScore > p)
            i++;

        while (faceobjects[j].fScore < p)
            j--;

        if (i <= j) {
            // swap
            std::swap(faceobjects[i], faceobjects[j]);

            i++;
            j--;
        }
    }

    #pragma omp parallel sections
    {
        #pragma omp section
        {
            if (left < j) QsortDescentInplace(faceobjects, left, j);
        }
        #pragma omp section
        {
            if (i < right) QsortDescentInplace(faceobjects, i, right);
        }
    }
}

static void QsortDescentInplace(std::vector<ObjBox>& faceobjects)
{
    if (faceobjects.empty())
        return;

    QsortDescentInplace(faceobjects, 0, faceobjects.size() - 1);
}

static inline float IntersectionArea(const RectInfo& a, const RectInfo& b)
{
    if (a.x > b.x + b.width || a.x + a.width < b.x ||
        a.y > b.y + b.height || a.y + a.height < b.y) {
        return 0.f;
    }

    float inter_width = std::min(a.x + a.width, b.x + b.width) - std::max(a.x, b.x);
    float inter_height = std::min(a.y + a.height, b.y + b.height) - std::max(a.y, b.y);

    return inter_width * inter_height;
}

static void NmsSortedBboxes(const std::vector<ObjBox>& faceobjects,
    std::vector<int>& picked, float nms_threshold)
{
    picked.clear();

    const int n = faceobjects.size();

    std::vector<float> areas(n);
    for (int i = 0; i < n; i++) {
        areas[i] = faceobjects[i].rect.width * faceobjects[i].rect.height;
    }

    for (int i = 0; i < n; i++) {
        const ObjBox& a = faceobjects[i];

        int keep = 1;
        for (int j = 0; j < (int)picked.size(); j++) {
            const ObjBox& b = faceobjects[picked[j]];
            // intersection over union
            float inter_area = IntersectionArea(a.rect, b.rect);
            float union_area = areas[i] + areas[picked[j]] - inter_area;
            if (inter_area / union_area > nms_threshold)
                keep = 0;
        }

        if (keep)
            picked.emplace_back(i);
    }
}

static HI_S32 SVP_NNIE_Yolov5_GetMaxVal(HI_S32 *pf32Val, HI_U32 u32Num, HI_U32 * pu32MaxValueIndex, HI_U32 offSet)
{
    HI_U32 i = 0;
    HI_S32 f32MaxTmp = 0;

    f32MaxTmp = pf32Val[0];
    *pu32MaxValueIndex = 0;
    for (i = 1; i < u32Num; i++)
    {
        int tmpIndex = offSet * i;
        if (pf32Val[tmpIndex] > f32MaxTmp)
        {
            f32MaxTmp = pf32Val[tmpIndex];
            *pu32MaxValueIndex = i;
        }
    }

    return f32MaxTmp;
}


static HI_S32 GetResult_V5(
    HI_S32 **pps32InputData,
    HI_U32 au32GridNumWidth[],
    HI_U32 au32GridNumHeight[],
    HI_U32 u32SrcWidth,
    HI_U32 u32SrcHeight,
    HI_U32 au32Stride[],
    HI_U32 u32NmsThresh,
    HI_U32 u32ConfThresh,
    Anchors af32Bias[ANCHOR_NUM][EACH_GRID_BIAS_NUM],
    HI_S32* ps32TmpBuf,
    std::vector<ObjBox> &objBoxs,
    GC_YOLO_VERSION yolo_version
    )
    
{
    HI_S32 *ps32InputBlob = NULL;
    HI_FLOAT *pf32Permute = NULL;
    SAMPLE_SVP_NNIE_YOLOV3_BBOX_S *pstBbox = NULL;
    HI_S32 *ps32AssistBuf = NULL;
    HI_U32 u32TotalBboxNum = 0;
    HI_U32 u32ChnOffset = 0;
    HI_U32 u32HeightOffset = 0;
    HI_U32 u32BboxNum = 0;
    HI_FLOAT f32StartX;
    HI_FLOAT f32StartY;
    HI_FLOAT f32Width;
    HI_FLOAT f32Height;
    HI_FLOAT f32ObjScore;
    HI_U32 u32MaxValueIndex = 0;
    HI_FLOAT f32MaxScore;
    HI_S32 s32ClassScore;
    HI_U32 u32ClassRoiNum;
    HI_U32 i = 0, j = 0;
    HI_U32 u32BlobSize = 0;
    HI_U32 u32MaxBlobSize = 0;
    BOOL modelHasSigmoid = FALSE; // 可考虑将sigmoid放入模型层，减少后处理耗时进行加速
    std::vector<ObjBox> detBoxs;
    pf32Permute = (HI_FLOAT*)ps32TmpBuf;
    int class_num = CLASS_NUM;
    int landmark_num = LANDMARK_NUM;
    HI_S32 attribute = (class_num + SAMPLE_SVP_NNIE_COORDI_NUM + GC_NNIE_OBJ_SCORE_NUM + landmark_num);

    for (int i = 0; i < BLOB_NUM; i++) { // blob
        ps32InputBlob = pps32InputData[i];
        u32ChnOffset = au32GridNumHeight[i] * au32Stride[i] / sizeof(HI_S32); 
        u32HeightOffset = au32Stride[i] / sizeof(HI_S32);

        // LOG_DEBUG("u32ChnOffset:[%d] u32HeightOffset:[%d] attribute:[%d]\n", u32ChnOffset, u32HeightOffset, attribute);

        for (int n = 0; n < ANCHOR_NUM; n++) { // anchor size
            for (HI_U32 h = 0; h < au32GridNumHeight[i]; h ++) {
                for (HI_U32 w = 0; w < u32HeightOffset; w ++) {
                    int index = SAMPLE_SVP_NNIE_COORDI_NUM * u32ChnOffset + w + h * u32HeightOffset + n * attribute * u32ChnOffset;
                    f32ObjScore = (HI_FLOAT)(ps32InputBlob[index]) / SAMPLE_SVP_NNIE_QUANT_BASE;
                    u32MaxValueIndex = 0;
                    if (!modelHasSigmoid) {
                        f32ObjScore = sigmoid(f32ObjScore);
                    }
                    if (f32ObjScore < (HI_FLOAT)u32ConfThresh / SAMPLE_SVP_NNIE_QUANT_BASE) {
                        continue;
                    }
                    f32MaxScore = (HI_FLOAT)(SVP_NNIE_Yolov5_GetMaxVal(&ps32InputBlob[(SAMPLE_SVP_NNIE_COORDI_NUM + GC_NNIE_OBJ_SCORE_NUM + landmark_num) * u32ChnOffset + w + h * u32HeightOffset + n * attribute * u32ChnOffset], 
                        class_num, &u32MaxValueIndex, u32ChnOffset)) / SAMPLE_SVP_NNIE_QUANT_BASE;
                    if (yolo_version != GC_YOLO_VERSION::YOLO_V5_ONLY_PLATE) {
                        if (!std::any_of(gc_app_config.base_config.alg_config.classes.begin(), gc_app_config.base_config.alg_config.classes.end(), [u32MaxValueIndex](int i){return i == u32MaxValueIndex;})) {
                            // LOG_DEBUG("class=%d is not being used", u32MaxValueIndex);
                            continue;
                        }
                    }
                    if (!modelHasSigmoid) {
                        f32MaxScore = sigmoid(f32MaxScore);
                    }
                    s32ClassScore = (HI_S32)(f32MaxScore * f32ObjScore * SAMPLE_SVP_NNIE_QUANT_BASE);
                    if (s32ClassScore > u32ConfThresh  && u32SrcHeight != 0 && u32SrcWidth != 0) {

                        // LOG_DEBUG("----------------------------------------------------------");
                        // LOG_DEBUG("f32ObjScore=%f, f32MaxScore=%f, s32ClassScore=%d, u32ConfThresh=%d", f32ObjScore, f32MaxScore, s32ClassScore, u32ConfThresh);

                        HI_FLOAT box_x = ps32InputBlob[0 * u32ChnOffset + w + h * u32HeightOffset + n * attribute * u32ChnOffset] * 1.f / SAMPLE_SVP_NNIE_QUANT_BASE;
                        HI_FLOAT box_y = ps32InputBlob[1 * u32ChnOffset + w + h * u32HeightOffset + n * attribute * u32ChnOffset] * 1.f / SAMPLE_SVP_NNIE_QUANT_BASE;
                        HI_FLOAT box_w = ps32InputBlob[2 * u32ChnOffset + w + h * u32HeightOffset + n * attribute * u32ChnOffset] * 1.f / SAMPLE_SVP_NNIE_QUANT_BASE;
                        HI_FLOAT box_h = ps32InputBlob[3 * u32ChnOffset + w + h * u32HeightOffset + n * attribute * u32ChnOffset] * 1.f / SAMPLE_SVP_NNIE_QUANT_BASE;

                        // LOG_DEBUG("box_x=%f, box_y=%f, box_w=%f, box_h=%f", box_x, box_y, box_w, box_h);
                    
                        box_x = modelHasSigmoid ? box_x:sigmoid(box_x);
                        box_y = modelHasSigmoid ? box_y:sigmoid(box_y);
                        box_w = modelHasSigmoid ? box_w:sigmoid(box_w);
                        box_h = modelHasSigmoid ? box_h:sigmoid(box_h);

                        // LOG_DEBUG("sigmoid: ");
                        // LOG_DEBUG("box_x=%f, box_y=%f, box_w=%f, box_h=%f", box_x, box_y, box_w, box_h);

                        f32StartX = (box_x * 2.0 - 0.5 + w) / au32GridNumWidth[i];
                        f32StartY = (box_y * 2.0 - 0.5 + h) / au32GridNumHeight[i];
                        f32Width =  box_w * 2 * box_w * 2 * af32Bias[i][n].anchorW / u32SrcWidth;
                        f32Height = box_h * 2 * box_h * 2 * af32Bias[i][n].anchorH / u32SrcHeight;

                        ObjBox obj;
                        obj.rect.x = (f32StartX - f32Width * 0.5f) * u32SrcWidth;
                        obj.rect.y = (f32StartY - f32Height * 0.5f) * u32SrcHeight;
                        obj.rect.width = f32Width * u32SrcWidth;
                        obj.rect.height = f32Height * u32SrcHeight;
                        obj.fScore = (HI_FLOAT)s32ClassScore / SAMPLE_SVP_NNIE_QUANT_BASE;
                        obj.enClass = u32MaxValueIndex;     

                        // landmarks
                        if (yolo_version == GC_YOLO_VERSION::YOLO_V5_ONLY_PLATE
                            || 
                            (yolo_version == GC_YOLO_VERSION::YOLO_V5_ONLY_PLATE_CAR
                                && std::find(gc_app_config.base_config.alg_config.plate_classes.begin(), gc_app_config.base_config.alg_config.plate_classes.end(), obj.enClass) != gc_app_config.base_config.alg_config.plate_classes.end()
                            )
                        ) {
                            /*
                                python code:

                                y[..., 0:2] = (y[..., 0:2] * 2. - 0.5 + self.grid[i].to(x[i].device)) * self.stride[i]  # xy
                                y[..., 2:4] = (y[..., 2:4] * 2) ** 2 * self.anchor_grid[i]  # wh                                

                                y = torch.full_like(x[i], 0)
                                class_range = list(range(5)) + list(range(13,13+self.nc))
                                y[..., class_range] = x[i][..., class_range].sigmoid()
                                y[..., 5:13] = x[i][..., 5:13]
                                #y = x[i].sigmoid()

                                y[..., 0:2] = (y[..., 0:2] * 2. - 0.5 + self.grid[i].to(x[i].device)) * self.stride[i]  # xy
                                y[..., 2:4] = (y[..., 2:4] * 2) ** 2 * self.anchor_grid[i]  # wh

                                #y[..., 5:15] = y[..., 5:15] * 8 - 4
                                y[..., 5:7]   = y[..., 5:7] *   self.anchor_grid[i] + self.grid[i].to(x[i].device) * self.stride[i] # landmark x1 y1
                                y[..., 7:9]   = y[..., 7:9] *   self.anchor_grid[i] + self.grid[i].to(x[i].device) * self.stride[i]# landmark x2 y2
                                y[..., 9:11]  = y[..., 9:11] *  self.anchor_grid[i] + self.grid[i].to(x[i].device) * self.stride[i]# landmark x3 y3
                                y[..., 11:13] = y[..., 11:13] * self.anchor_grid[i] + self.grid[i].to(x[i].device) * self.stride[i]# landmark x4 y4                        
                            */                            
                            HI_FLOAT lm_x0 = ps32InputBlob[5 * u32ChnOffset + w + h * u32HeightOffset + n * attribute * u32ChnOffset] * 1.f / SAMPLE_SVP_NNIE_QUANT_BASE;
                            HI_FLOAT lm_y0 = ps32InputBlob[6 * u32ChnOffset + w + h * u32HeightOffset + n * attribute * u32ChnOffset] * 1.f / SAMPLE_SVP_NNIE_QUANT_BASE;
                            HI_FLOAT lm_x1 = ps32InputBlob[7 * u32ChnOffset + w + h * u32HeightOffset + n * attribute * u32ChnOffset] * 1.f / SAMPLE_SVP_NNIE_QUANT_BASE;
                            HI_FLOAT lm_y1 = ps32InputBlob[8 * u32ChnOffset + w + h * u32HeightOffset + n * attribute * u32ChnOffset] * 1.f / SAMPLE_SVP_NNIE_QUANT_BASE;
                            HI_FLOAT lm_x2 = ps32InputBlob[9 * u32ChnOffset + w + h * u32HeightOffset + n * attribute * u32ChnOffset] * 1.f / SAMPLE_SVP_NNIE_QUANT_BASE;
                            HI_FLOAT lm_y2 = ps32InputBlob[10 * u32ChnOffset + w + h * u32HeightOffset + n * attribute * u32ChnOffset] * 1.f / SAMPLE_SVP_NNIE_QUANT_BASE;
                            HI_FLOAT lm_x3 = ps32InputBlob[11 * u32ChnOffset + w + h * u32HeightOffset + n * attribute * u32ChnOffset] * 1.f / SAMPLE_SVP_NNIE_QUANT_BASE;
                            HI_FLOAT lm_y3 = ps32InputBlob[12 * u32ChnOffset + w + h * u32HeightOffset + n * attribute * u32ChnOffset] * 1.f / SAMPLE_SVP_NNIE_QUANT_BASE;

                            // LOG_DEBUG("landmarks=[%f, %f], [%f, %f], [%f, %f], [%f, %f]", lm_x0, lm_y0, lm_x1, lm_y1, lm_x2, lm_y2, lm_x3, lm_y3);
                            // LOG_DEBUG("au32GridNumWidth[i]=%d, u32SrcWidth=%d, af32Bias[i][n].anchorW=%d", au32GridNumWidth[i], u32SrcWidth, af32Bias[i][n].anchorW);
                            // LOG_DEBUG("au32GridNumHeight[i]=%d, u32SrcHeight=%d, af32Bias[i][n].anchorH=%d", au32GridNumHeight[i], u32SrcHeight, af32Bias[i][n].anchorH);
                            // LOG_DEBUG("u32HeightOffset=%d, au32Stride[i]=%d, w=%d, h=%d,f32Width=%f, f32Height=%f", u32HeightOffset, au32Stride[i], w, h, f32Width, f32Height);

                            HI_FLOAT f_lm_x0 = lm_x0 * af32Bias[i][n].anchorW + w * 1.f / au32GridNumWidth[i] * u32SrcWidth;
                            HI_FLOAT f_lm_y0 = lm_y0 * af32Bias[i][n].anchorH + h * 1.f / au32GridNumHeight[i] * u32SrcHeight;
                            HI_FLOAT f_lm_x1 = lm_x1 * af32Bias[i][n].anchorW + w * 1.f / au32GridNumWidth[i] * u32SrcWidth;
                            HI_FLOAT f_lm_y1 = lm_y1 * af32Bias[i][n].anchorH + h * 1.f / au32GridNumHeight[i] * u32SrcHeight;
                            HI_FLOAT f_lm_x2 = lm_x2 * af32Bias[i][n].anchorW + w * 1.f / au32GridNumWidth[i] * u32SrcWidth;
                            HI_FLOAT f_lm_y2 = lm_y2 * af32Bias[i][n].anchorH + h * 1.f / au32GridNumHeight[i] * u32SrcHeight;
                            HI_FLOAT f_lm_x3 = lm_x3 * af32Bias[i][n].anchorW + w * 1.f / au32GridNumWidth[i] * u32SrcWidth;
                            HI_FLOAT f_lm_y3 = lm_y3 * af32Bias[i][n].anchorH + h * 1.f / au32GridNumHeight[i] * u32SrcHeight;

                            obj.landmark.x0 = f_lm_x0;
                            obj.landmark.y0 = f_lm_y0;
                            obj.landmark.x1 = f_lm_x1;
                            obj.landmark.y1 = f_lm_y1;
                            obj.landmark.x2 = f_lm_x2;
                            obj.landmark.y2 = f_lm_y2;
                            obj.landmark.x3 = f_lm_x3;
                            obj.landmark.y3 = f_lm_y3;

                            // LOG_DEBUG("final landmarks=[%f, %f], [%f, %f], [%f, %f], [%f, %f]", f_lm_x0, f_lm_y0, f_lm_x1, f_lm_y1, f_lm_x2, f_lm_y2, f_lm_x3, f_lm_y3);
                            // LOG_DEBUG("================================================================================================");

                        }
                        detBoxs.emplace_back(obj);
                    }
                }
            }
        }
    }

    // LOG_DEBUG("detjBoxs.size() :%d", detBoxs.size());

    QsortDescentInplace(detBoxs);
    // apply nms with nms_threshold
    std::vector<int> picked;
    NmsSortedBboxes(detBoxs, picked, (float)u32NmsThresh / SAMPLE_SVP_NNIE_QUANT_BASE);

    int count = picked.size();

    for (size_t i = 0; i < picked.size(); i++) {
        size_t z = picked[i];
        objBoxs.emplace_back(detBoxs[z]);
    }
    
    // LOG_DEBUG("objBoxs.size() :%d", objBoxs.size());

    for (auto obj: objBoxs) {
        if (yolo_version == GC_YOLO_VERSION::YOLO_V5_ONLY_PLATE
            || 
            (yolo_version == GC_YOLO_VERSION::YOLO_V5_ONLY_PLATE_CAR
                && std::find(gc_app_config.base_config.alg_config.plate_classes.begin(), gc_app_config.base_config.alg_config.plate_classes.end(), obj.enClass) != gc_app_config.base_config.alg_config.plate_classes.end()
            )
        ) {
            // LOG_DEBUG("obj.enClass=%d, obj.x=%d, obj.y=%d, obj.w=%d, obj.h=%d, landmarks=[%d, %d], [%d, %d], [%d, %d], [%d, %d], obj.score=%f",
                // obj.enClass, obj.rect.x, obj.rect.y, obj.rect.width, obj.rect.height, obj.landmark.x0, obj.landmark.y0, obj.landmark.x1, obj.landmark.y1, obj.landmark.x2, obj.landmark.y2, obj.landmark.x3, obj.landmark.y3, obj.fScore);
        } else {
            // LOG_DEBUG("obj.enClass=%d, obj.x=%d, obj.y=%d, obj.w=%d, obj.h=%d, obj.score=%f", obj.enClass, obj.rect.x, obj.rect.y, obj.rect.width, obj.rect.height, obj.fScore);
        }
    }

    // LOG_DEBUG("\n\n\n\n");

    return HI_SUCCESS;

}

void NNIE::PostProcess(std::vector<ObjBox> &objBoxs)
{
    HI_S32 *aps32InputBlob[BLOB_NUM] = { 0 };
    HI_U32 au32Stride[BLOB_NUM] = { 0 };
    int i = 0;
    for (i = 0; i < BLOB_NUM; i++) {
        aps32InputBlob[i] = (HI_S32*)m_NnieParam.astSegData[0].astDst[i].u64VirAddr;
        au32Stride[i] = m_NnieParam.astSegData[0].astDst[i].u32Stride;
        // LOG_DEBUG("BLOB=%d, size=%d, au32Stride=%d", i, sizeof(aps32InputBlob[i])/sizeof(HI_S32*), au32Stride[i]);
    }

    GetResult_V5(aps32InputBlob,
        m_SoftwareParam.au32GridNumWidth,
        m_SoftwareParam.au32GridNumHeight,
        m_SoftwareParam.u32OriImWidth,
        m_SoftwareParam.u32OriImHeight,
        au32Stride, 
        m_SoftwareParam.u32NmsThresh,
        m_SoftwareParam.u32ConfThresh,
        m_SoftwareParam.anchors,
        (HI_S32*)m_SoftwareParam.stGetResultTmpBuf.u64VirAddr,
        objBoxs,
        m_yolo_version
        );
}

/**
 * @brief 
 * 
 * @param filePath 
 * @param img yuv frame
 * @param objBoxs 
 * @return int 
 */
int NNIE::InferenceFile(const char* filePath, ImageInfo& img, std::vector<ObjBox> &objBoxs)
{
    ReadImgFile(filePath, img);

    FillSrcData(img);

    // forward
    NNIE_DATA_INDEX_S inputDataIdx = {};
    NNIE_DATA_INDEX_S procSegIdx = {};
    Forward(&inputDataIdx, &procSegIdx);

    PostProcess(objBoxs);

}

int NNIE::InferenceYuv(HI_CHAR *pcSrcYUV, std::vector<ObjBox> &objBoxs)
{
    struct timespec time1 = {0, 0};
    struct timespec time2 = {0, 0};

    FillSrcData(pcSrcYUV);

    // forward
    NNIE_DATA_INDEX_S inputDataIdx = {};
    NNIE_DATA_INDEX_S procSegIdx = {};
    Forward(&inputDataIdx, &procSegIdx);

    clock_gettime(CLOCK_BOOTTIME, &time1);

    PostProcess(objBoxs);

    clock_gettime(CLOCK_BOOTTIME, &time2);
    // LOG_DEBUG("PostProcess_time: %04lu ms", (time2.tv_sec - time1.tv_sec) *1000 + (time2.tv_nsec - time1.tv_nsec)/1000000);   

    return HW_OK;
}

int NNIE::ParamInit()
{
    m_NnieCfg.u32MaxInputNum = 1;               // max input image num in each batch
    m_NnieCfg.u32MaxRoiNum = 0;
    m_NnieCfg.aenNnieCoreId[0] = SVP_NNIE_ID_0; // set NNIE core
    if (SAMPLE_SVP_NNIE_Yolov3_ParamInit() != HW_OK) {
        LOG_ERROR("Initalize the NNie parameter failed");
        return ERR;  
    } 
    LOG_DEBUG("Initalize the NNie parameter successfully");
    return HW_OK;
}

void NNIE::Init()
{
    m_fd_alg = GetFd();
    memset_s(&m_NnieModel, sizeof(m_NnieModel), 0, sizeof(m_NnieModel));
    memset_s(&m_NnieParam, sizeof(m_NnieParam), 0, sizeof(m_NnieParam));
    memset_s(&m_NnieCfg, sizeof(m_NnieCfg), 0, sizeof(m_NnieCfg));
    // memset_s(&m_NnieCfg, sizeof(m_NnieCfg), 0, sizeof(stNnieCfg_SDC));
    m_utilsSrv = std::make_shared<UtilsService>();
}

HI_S32 NNIE::FillSrcData(HI_U8 *pData)
{
    FILE *fp = NULL;
    HI_U32 i = 0, j = 0, n = 0;
    HI_U32 u32Height = 0, u32Width = 0, u32Chn = 0, u32Stride = 0, u32Dim = 0;
    HI_U32 u32VarSize = 0;
    HI_S32 s32Ret = HI_SUCCESS;
    HI_U8 *pu8PicAddr = NULL;
    HI_U32 *pu32StepAddr = NULL;
    HI_U32 u32TotalStepNum = 0;

    HI_BOOL bRBG2BGR = HI_TRUE;  // 送入模型的通道顺序是否调整
    HI_U32 u32SegIdx = 0;
    HI_U32 u32NodeIdx = 0;
// RBG => BGR
#define B_BASE_OFFSET (1 * u32Stride * u32Height)
#define G_BASE_OFFSET (2 * u32Stride * u32Height)
#define R_BASE_OFFSET (0 * u32Stride * u32Height)
    HI_U8 *p_B_data = HI_NULL;
    HI_U8 *p_G_data = HI_NULL;
    HI_U8 *p_R_data = HI_NULL;

    /*get data size*/
    if (SVP_BLOB_TYPE_U8 <= m_NnieParam.astSegData[u32SegIdx].astSrc[u32NodeIdx].enType &&
        SVP_BLOB_TYPE_YVU422SP >= m_NnieParam.astSegData[u32SegIdx].astSrc[u32NodeIdx].enType) {
        u32VarSize = sizeof(HI_U8);
    } else {
        u32VarSize = sizeof(HI_U32);
    }

    /*fill src data*/
    if (SVP_BLOB_TYPE_SEQ_S32 == m_NnieParam.astSegData[u32SegIdx].astSrc[u32NodeIdx].enType) {
        u32Dim = m_NnieParam.astSegData[u32SegIdx].astSrc[u32NodeIdx].unShape.stSeq.u32Dim;
        u32Stride = m_NnieParam.astSegData[u32SegIdx].astSrc[u32NodeIdx].u32Stride;
        pu32StepAddr = (HI_U32 *)(m_NnieParam.astSegData[u32SegIdx].astSrc[u32NodeIdx].unShape.stSeq.u64VirAddrStep);
        pu8PicAddr = (HI_U8 *)(m_NnieParam.astSegData[u32SegIdx].astSrc[u32NodeIdx].u64VirAddr);
        for (n = 0; n < m_NnieParam.astSegData[u32SegIdx].astSrc[u32NodeIdx].u32Num; n++) {
            for (i = 0; i < *(pu32StepAddr + n); i++) {
                s32Ret = fread(pu8PicAddr, u32Dim * u32VarSize, 1, fp);
                SAMPLE_SVP_CHECK_EXPR_GOTO(1 != s32Ret, FAIL, SAMPLE_SVP_ERR_LEVEL_ERROR,
                                           "Error,Read image file failed!\n");
                pu8PicAddr += u32Stride;
            }
            u32TotalStepNum += *(pu32StepAddr + n);
        }
        m_utilsSrv->SDCFlushCache(m_NnieParam.astSegData[u32SegIdx].astSrc[u32NodeIdx].u64PhyAddr,
                                  (HI_VOID *)m_NnieParam.astSegData[u32SegIdx].astSrc[u32NodeIdx].u64VirAddr,
                                  u32TotalStepNum * u32Stride);
    } else {
        u32Height = m_NnieParam.astSegData[u32SegIdx].astSrc[u32NodeIdx].unShape.stWhc.u32Height;
        u32Width = m_NnieParam.astSegData[u32SegIdx].astSrc[u32NodeIdx].unShape.stWhc.u32Width;
        u32Chn = m_NnieParam.astSegData[u32SegIdx].astSrc[u32NodeIdx].unShape.stWhc.u32Chn;
        u32Stride = m_NnieParam.astSegData[u32SegIdx].astSrc[u32NodeIdx].u32Stride;
        pu8PicAddr = (HI_U8 *)(m_NnieParam.astSegData[u32SegIdx].astSrc[u32NodeIdx].u64VirAddr);
        if (SVP_BLOB_TYPE_YVU420SP == m_NnieParam.astSegData[u32SegIdx].astSrc[u32NodeIdx].enType) {
            std::cout << "model data type is yuv420p\n";
            for (n = 0; n < m_NnieParam.astSegData[u32SegIdx].astSrc[u32NodeIdx].u32Num; n++) {
                UINT32 uiDataSize = u32Width * u32Height * 3 / 2;
                memset_s(pu8PicAddr, uiDataSize, 0, uiDataSize);
                memcpy_s(pu8PicAddr, uiDataSize, pData, uiDataSize);
                // SaveYuv(pData);
            }
        } else if (SVP_BLOB_TYPE_YVU422SP == m_NnieParam.astSegData[u32SegIdx].astSrc[u32NodeIdx].enType) {
            for (n = 0; n < m_NnieParam.astSegData[u32SegIdx].astSrc[u32NodeIdx].u32Num; n++) {
                for (i = 0; i < u32Height * 2; i++) {
                    s32Ret = fread(pu8PicAddr, u32Width * u32VarSize, 1, fp);
                    SAMPLE_SVP_CHECK_EXPR_GOTO(1 != s32Ret, FAIL, SAMPLE_SVP_ERR_LEVEL_ERROR,
                                               "Error,Read image file failed!\n");
                    pu8PicAddr += u32Stride;
                }
            }
        } else {
            std::cout << "model data type is u8\n";
            for (n = 0; n < m_NnieParam.astSegData[u32SegIdx].astSrc[u32NodeIdx].u32Num; n++) {
                for (i = 0; i < u32Chn; i++) {
                    for (j = 0; j < u32Height; j++) {
                        memcpy(pu8PicAddr, pData, u32Width * u32VarSize);
                        pData += u32Width * u32VarSize;
                        pu8PicAddr += u32Stride;
                    }
                }
            }
        }
        m_utilsSrv->SDCFlushCache(m_NnieParam.astSegData[u32SegIdx].astSrc[u32NodeIdx].u64PhyAddr,
                                  (HI_VOID *)m_NnieParam.astSegData[u32SegIdx].astSrc[u32NodeIdx].u64VirAddr,
                                  m_NnieParam.astSegData[u32SegIdx].astSrc[u32NodeIdx].u32Num * u32Chn * u32Height *
                                      u32Stride);
    }
    if (fp != HI_NULL)
        fclose(fp);
    return HI_SUCCESS;

FAIL:
    if (fp != HI_NULL)
        fclose(fp);
    fclose(fp);
    return HI_FAILURE;
}

void NNIE::decode_outputs(int *indexs, float *confs, int output_size, std::string &plate, float &plate_conf, std::vector<float>& char_conf)
{
    std::string pre_str = "#";
    float total_conf = 0.0;
    int valid_char_nums = 0;
    for (int i = 0; i < output_size; i++) {
        int index = indexs[i];
        if (index < int(PLATE_CHAR_LIST.size())) {
            if (PLATE_CHAR_LIST[index] != "#" && PLATE_CHAR_LIST[index] != pre_str && PLATE_CHAR_LIST[index]!="电动备案") {
                plate += PLATE_CHAR_LIST[index];
                char_conf.emplace_back(confs[i]);
                total_conf += confs[i];
                valid_char_nums++;
            }
            pre_str = PLATE_CHAR_LIST[index];
        }
    }

    plate_conf = total_conf / valid_char_nums;
}

void NNIE::PostLprProcess(std::string &plate, float &plate_conf, std::vector<float>& char_conf)
{
    HI_U32 u32SegIdx = 0;
    HI_U32 u32NodeIdx = 0;

    HI_U32 u32Height = m_NnieParam.astSegData[u32SegIdx].astDst[u32NodeIdx].unShape.stWhc.u32Height;
    HI_U32 u32Width = m_NnieParam.astSegData[u32SegIdx].astDst[u32NodeIdx].unShape.stWhc.u32Width;
    HI_U32 u32Chn = m_NnieParam.astSegData[u32SegIdx].astDst[u32NodeIdx].unShape.stWhc.u32Chn;
    HI_U32 u32Stride = m_NnieParam.astSegData[u32SegIdx].astDst[u32NodeIdx].u32Stride;
    HI_U32 u32Num = m_NnieParam.astSegData[u32SegIdx].astDst[u32NodeIdx].u32Num;

    std::cout << "net output size: " << u32Chn << " " << u32Height << " " << u32Width << "\n";

    // 获取网络输出
    HI_S32 *ps32ResultAddr = (HI_S32 *)(m_NnieParam.astSegData[u32SegIdx].astDst[u32NodeIdx].u64VirAddr);

    // int->float
    float *out = new float[u32Width];
    for (int k = 0; k < u32Width; k++) {
        *(out + k) = (*(ps32ResultAddr + k)) * 1.0f / SAMPLE_SVP_NNIE_QUANT_BASE;
    }

    // 输出维度（1,1638）->(21,78)
    float out2[LPR_MODEL_OUTPUT_SIZE_HEIGHT][LPR_MODEL_OUTPUT_SIZE_WIDTH];
    for (int ii = 0; ii < LPR_MODEL_OUTPUT_SIZE_HEIGHT; ii++) {
        for (int jj = 0; jj < LPR_MODEL_OUTPUT_SIZE_WIDTH; jj++) {
            out2[ii][jj] = out[ii * LPR_MODEL_OUTPUT_SIZE_WIDTH + jj];
        }
    }

    // 获取车牌每个预测字符的置信度及置信度最大的下标
    float confs[LPR_MODEL_OUTPUT_SIZE_HEIGHT];
    int indexs[LPR_MODEL_OUTPUT_SIZE_HEIGHT];
    for (int ii = 0; ii < LPR_MODEL_OUTPUT_SIZE_HEIGHT; ii++) {
        float maxValue = *std::max_element(out2[ii], out2[ii] + LPR_MODEL_OUTPUT_SIZE_WIDTH);
        int maxPosition = std::max_element(out2[ii], out2[ii] + LPR_MODEL_OUTPUT_SIZE_WIDTH) - out2[ii];
        confs[ii] = maxValue;
        indexs[ii] = maxPosition;
    }

    // 过滤掉"#"字符，得到最终车牌号+置信度（有效字符的置信度平均值）
    decode_outputs(indexs, confs, LPR_MODEL_OUTPUT_SIZE_HEIGHT, plate, plate_conf, char_conf);

    delete[] out;
}

int NNIE::InferenceFile(const char *filePath, std::string &plate, float &plate_conf, std::vector<float>& char_conf)
{
    unsigned char *inputBlob = new unsigned char[LPR_MODEL_INPUT_SIZE_HEIGHT * LPR_MODEL_INPUT_SIZE_WIDTH * 3];
    ReadLprImage(filePath, inputBlob);

    FillSrcData(inputBlob);

    // forward
    NNIE_DATA_INDEX_S inputDataIdx = {};
    NNIE_DATA_INDEX_S procSegIdx = {};
    Forward(&inputDataIdx, &procSegIdx);

    PostLprProcess(plate, plate_conf, char_conf);
    delete[] inputBlob;
}

int NNIE::InferenceMat(const cv::Mat &img, std::string &plate, float &plate_conf, std::vector<float>& char_conf)
{
    unsigned char *inputBlob = new unsigned char[LPR_MODEL_INPUT_SIZE_HEIGHT * LPR_MODEL_INPUT_SIZE_WIDTH * 3];
    ReadLprMat(img, inputBlob);

    FillSrcData(inputBlob);

    // forward
    NNIE_DATA_INDEX_S inputDataIdx = {};
    NNIE_DATA_INDEX_S procSegIdx = {};
    Forward(&inputDataIdx, &procSegIdx);

    PostLprProcess(plate, plate_conf, char_conf);
    delete[] inputBlob;
}


}